package Leetcode100Hot;

import org.junit.Test;

/*
接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图，计算按此排列的柱子，下雨之后能接多少雨水。

示例 1：
输入：height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出：6
解释：上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图，在这种情况下，可以接 6 个单位的雨水（蓝色部分表示雨水）。
示例 2：
输入：height = [4,2,0,3,2,5]
输出：9

提示：
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
 */
public class _55接雨水 {

    @Test
    public void test(){
        System.out.println(trap(new int[]{4,2,0,3,2,5}));
    }

    //WA
    public int trap(int[] height) {
        int res = 0;
        int n = height.length;
        int left = 0,right = 0;
        while (left < n && height[left + 1] >= height[left]) {
            left++;
        }
        while (true){
            int[] helper = helper(height, left);
            left = helper[0];
            right = helper[1];
            if (right >= n) break;
            int min = Math.min(height[left], height[right]);
            for(int i = left + 1; i < right; i++){
                res += min - height[i];
            }
            left = right;
        }
        return res;
    }

    public int[] helper(int[] height, int left) {
        int[] res = new int[]{left,-1};
        int n = height.length;
        while (left + 1 < n && height[left + 1] <= height[left]) {
            left++;
        }
        int right = left + 1;
        while (right + 1 < n && height[right + 1] >= height[right]) {
            right++;
        }
        res[1] = right;
        return res;
    }

    //官解：方法一：动态规划
    //ps: 官解链接思路很清晰
    //O(n) O(n)
    /*
    作者：力扣官方题解
    链接：https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
     */
    class Solution {
        public int trap(int[] height) {
            int n = height.length;
            if (n == 0) {
                return 0;
            }

            int[] leftMax = new int[n];
            leftMax[0] = height[0];
            for (int i = 1; i < n; ++i) {
                leftMax[i] = Math.max(leftMax[i - 1], height[i]);
            }

            int[] rightMax = new int[n];
            rightMax[n - 1] = height[n - 1];
            for (int i = n - 2; i >= 0; --i) {
                rightMax[i] = Math.max(rightMax[i + 1], height[i]);
            }

            int ans = 0;
            for (int i = 0; i < n; ++i) {
                ans += Math.min(leftMax[i], rightMax[i]) - height[i];
            }
            return ans;
        }
    }

    //官解：方法三：双指针
    //O(n) O(1)
    /*
    作者：力扣官方题解
    链接：https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
     */
    class Solution3 {
        public int trap(int[] height) {
            int ans = 0;
            int left = 0, right = height.length - 1;
            int leftMax = 0, rightMax = 0;
            while (left < right) {
                leftMax = Math.max(leftMax, height[left]);
                rightMax = Math.max(rightMax, height[right]);
                if (height[left] < height[right]) {
                    ans += leftMax - height[left];
                    ++left;
                } else {
                    ans += rightMax - height[right];
                    --right;
                }
            }
            return ans;
        }
    }

}
